﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;

namespace CrayonsBox.Drawing
{
    public class DepricatedLayer : Document.Drawable
    {
        public event EventHandler OnSelectStateChanged;

        protected byte[] m_pixels;
        protected Bitmap m_image;
        protected Document m_docx;
        protected Color m_alphaColor; // use for picture 24 bit

        public bool IsMovable { get; set; }

        public override Boolean IsSelected
        {
            get
            {
                return base.IsSelected;
            }

            set
            {
                bool stateChanged = (base.IsSelected != value);
                base.IsSelected = value;
                if (stateChanged && OnSelectStateChanged != null)
                {
                    OnSelectStateChanged(this, new EventArgs());
                }

            }
        }

        public Color AlphaColor
        {
            get { return m_alphaColor; }
            set { m_alphaColor = value; }
        }

        public override Size Dimension
        {
            get { return base.Dimension; }
            set
            {
                base.Dimension = value;
                m_pixels = new byte[4 * base.Dimension.Width * base.Dimension.Height];
            }
        }

        public Bitmap LayerBitmap
        {
            get
            {
                return m_image;
            }
        }

        public DepricatedLayer(Document doc) : base(doc)
        {
            this.IsVisible = false;
        }

        public void RefreshImage()
        {
            if (m_image == null || m_image.PixelFormat != PixelFormat.Format24bppRgb) return;

            for (int i = 0; i < m_pixels.Length; i += 4)
            {
                if (m_pixels[i] == m_alphaColor.B &&
                    m_pixels[i + 1] == m_alphaColor.G &&
                    m_pixels[i + 2] == m_alphaColor.R
                    )
                    m_pixels[i + 3] = 0;
                else
                    m_pixels[i + 3] = 255;
            }
        }

        public Color GetPixel(int x, int y)
        {
            byte a = m_pixels[4 * (y * Dimension.Width + x) + 3];
            byte r = m_pixels[4 * (y * Dimension.Width + x) + 2];
            byte g = m_pixels[4 * (y * Dimension.Width + x) + 1];
            byte b = m_pixels[4 * (y * Dimension.Width + x)];
            return Color.FromArgb(a, r, g, b);
        }

        public static Color GetPixel(byte[] bgra, Size sz, int x, int y)
        {
            byte a = bgra[4 * (y * sz.Width + x) + 3];
            byte r = bgra[4 * (y * sz.Width + x) + 2];
            byte g = bgra[4 * (y * sz.Width + x) + 1];
            byte b = bgra[4 * (y * sz.Width + x)];
            return Color.FromArgb(a, r, g, b);
        }

        public void LoadImage(String imgPath)
        {
            Bitmap bmp = new Bitmap(imgPath);
            LoadBitmap(bmp);          
        }

        public void LoadBitmap(Bitmap bmp)
        {
            this.m_image = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppArgb); // add padding pixel for bitmap to prepare for scaling
            this.Dimension = new Size(m_image.Width, m_image.Height);

            if (m_image.PixelFormat == PixelFormat.Format32bppArgb) //recreate 32-bits bitmap
            {
                BitmapData rbmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                BitmapData wbmd = m_image.LockBits(new Rectangle(0, 0, m_image.Width, m_image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

                for (int i = 0; i < bmp.Height; i++)
                {
                    Utils.CopyMemory(wbmd.Scan0 + (i * wbmd.Stride), rbmd.Scan0 + (i * rbmd.Stride), rbmd.Stride);
                }
                bmp.UnlockBits(rbmd);
                m_image.UnlockBits(wbmd);
            }
            //else if (m_image.PixelFormat == PixelFormat.Format24bppRgb)
            //{
            //    BitmapData bmd = m_image.LockBits(new Rectangle(0, 0, m_image.Width, m_image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            //    Size = new Size(m_image.Width, m_image.Height);

            //    IntPtr ptr = bmd.Scan0;

            //    int bytes = Math.Abs(bmd.Stride) * m_image.Height;
            //    byte[] rgbValues = new byte[bytes];

            //    Marshal.Copy(ptr, rgbValues, 0, bytes);
            //    int f = 1;
            //    for (int i = 0; i < rgbValues.Length; i += 3)
            //    {
            //        // calculate RGB
            //        m_pixels[(i + f) - 1] = rgbValues[i];
            //        m_pixels[(i + f)] = rgbValues[i + 1];
            //        m_pixels[(i + f) + 1] = rgbValues[i + 2];
            //        // default alpha
            //        /*
            //        // Test: set alpha where white took place
            //        if (m_pixels[(i + f) - 1] == 124 &&
            //            m_pixels[(i + f)] == 91 &&
            //            m_pixels[(i + f) + 1] == 17
            //            )
            //            m_pixels[(i + f) + 2] = 0;
            //        else*/
            //        m_pixels[(i + f) + 2] = 255;
            //        f++;
            //    }
            //    m_image.UnlockBits(bmd);
            //}
        }

        public override void Draw()
        {
            if (!IsVisible)
                return;
            
            //Draw content of layer
            Matrix m = Doc.Painter.Transform;

            Doc.Painter.ResetTransform();

            Point localOrigin = Point.Empty;

            localOrigin.Offset((int)(-Doc.Viewport.X * Doc.ZoomRate),(int)(-Doc.Viewport.Y * Doc.ZoomRate));

            localOrigin.Offset((int)(Location.X * Doc.ZoomRate), (int)(Location.Y * Doc.ZoomRate));

            RectangleF srect = new RectangleF(-0.5f, -0.5f, LayerBitmap.Width, LayerBitmap.Height);
            RectangleF drect = new RectangleF(0, 0, LayerBitmap.Width, LayerBitmap.Height);

            Doc.Painter.TranslateTransform(localOrigin.X, localOrigin.Y);

            Matrix beforeScale = Doc.Painter.Transform;

            Doc.Painter.ScaleTransform(Doc.ZoomRate, Doc.ZoomRate);

            Doc.Painter.DrawImage(LayerBitmap, drect, srect, GraphicsUnit.Pixel);

            Doc.Painter.Transform = beforeScale;

            if (IsSelected)
            {
                float[] dashValues = { 5, 5 };
                Pen blpen = new Pen(Color.FromArgb(51, 153, 255), 1);
                blpen.DashPattern = dashValues;
                SolidBrush bbr = new SolidBrush(Color.FromArgb(51, 153, 255));

                Rectangle tmpRec = new Rectangle(0, 0,
                    (int)(Boundary.Width * Doc.ZoomRate),
                    (int)(Boundary.Height * Doc.ZoomRate)
                );

                Doc.Painter.DrawLine(blpen, tmpRec.Left, tmpRec.Top, tmpRec.Right, tmpRec.Top);
                Doc.Painter.DrawLine(blpen, tmpRec.Right, tmpRec.Top, tmpRec.Right, tmpRec.Bottom);
                Doc.Painter.DrawLine(blpen, tmpRec.Right, tmpRec.Bottom, tmpRec.Left, tmpRec.Bottom);
                Doc.Painter.DrawLine(blpen, tmpRec.Left, tmpRec.Bottom, tmpRec.Left, tmpRec.Top);
            }

            Doc.Painter.Transform = m;
        }
    }

    public class DepricatedLayerCollection
    {
        protected Document m_document;

        protected List<DepricatedLayer> mLayers;

        protected List<DepricatedLayer> m_selectedLayers;

        protected Size mViewSize;

        protected byte[] mDisplayed;

        public Bitmap mDisplayedBitmap;

        public DepricatedLayer this[int idx]
        {
            get
            {
                return mLayers[idx];
            }
        }

        public List<DepricatedLayer> SelectedLayers
        {
            get
            {
                return m_selectedLayers;
            }
        }

        public Int32 Count
        {
            get { return mLayers.Count; }
        }

        public Size ViewSize
        {
            get
            {
                return new Size(mViewSize.Width, mViewSize.Height);
            }

            set
            {
                mViewSize = value;
                mDisplayed = new byte[mViewSize.Width * mViewSize.Height * 4];
                mDisplayedBitmap = new Bitmap(mViewSize.Width + 2, mViewSize.Height + 2, PixelFormat.Format32bppArgb);
            }
        }

        public byte[] ViewData
        {
            get
            {
                return mDisplayed;
            }
        }

        public Bitmap ViewBitmap
        {
            get
            {
                return mDisplayedBitmap;
            }
        }

        public DepricatedLayerCollection(Document document)
        {
            m_document = document;
            mLayers = new List<DepricatedLayer>();
            m_selectedLayers = new List<DepricatedLayer>();
            mDisplayed = null;
            mDisplayedBitmap = null;
        }

        public void HideAll()
        {
            foreach (DepricatedLayer l in mLayers)
            {
                l.IsVisible = false;
                l.IsSelected = false;
            }
        }

        public void AddLayer(String pathToImage)
        {
            DepricatedLayer layer = new DepricatedLayer(m_document);
            layer.LoadImage(pathToImage);
            mLayers.Add(layer);
        }

        public void AddLayer(Bitmap image)
        {
            DepricatedLayer new_layer = new DepricatedLayer(m_document);
            new_layer.LoadBitmap(image);
            new_layer.OnSelectStateChanged += ALayer_OnSelectStateChanged;
            mLayers.Add(new_layer);
        }

        private void ALayer_OnSelectStateChanged(object sender, EventArgs e)
        {
            DepricatedLayer l = sender as DepricatedLayer;
            if (l.IsSelected)
            {
                m_selectedLayers.Add(l);
            }
            else
            {
                if (m_selectedLayers.Contains(l))
                    m_selectedLayers.Remove(l);
            }
        }
    }
}
